package cn.virens.cmpt.database;

import java.sql.SQLException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.druid.pool.DruidDataSource;

import cn.virens.app.AppConfig;
import cn.virens.app.cmpt.Component;

public class DatabaseManagerImpl implements DatabaseManager, Component {
	private final Logger logger = LoggerFactory.getLogger(DatabaseManagerImpl.class);

	private final ThreadLocal<DatabaseConnoction> local = new ThreadLocal<>();
	private final DruidDataSource dataSource = new DruidDataSource();

	@Override
	public DatabaseConnoction getConnection() throws SQLException {
		DatabaseConnoction conn = local.get();

		// 连接不存在 | 连接被关闭
		if (conn == null || conn.isClosed()) {
			local.set(conn = new DatabaseConnoction(dataSource));
		}

		return conn;
	}

	@Override
	public DatabaseManager execute(DatabaseQueryExecute execute) {
		DatabaseConnoction connoction = null;

		try {
			connoction = getConnection();
			connoction.setAutoCommit(true);

			// 执行查询
			execute.execute(connoction);
		} catch (Exception e) {
			logger.error("SQL异常:" + e.getMessage(), e);
		}

		return this;
	}

	@Override
	public DatabaseManager transactionExecute(DatabaseQueryExecute execute) {
		DatabaseConnoction connoction = null;

		try {
			connoction = getConnection();
			connoction.setAutoCommit(false);

			// 执行查询
			execute.execute(connoction);

			// 提交查询
			connoction.commit();
		} catch (Exception e) {
			logger.error("SQL异常:" + e.getMessage(), e);

			try {
				connoction.rollback();
			} catch (Exception e2) {
				logger.error("回滚异常:" + e2.getMessage(), e2);
			}
		}

		return this;
	}

	@Override
	public void initialize(AppConfig config) throws Exception {
		this.dataSource.setDriverClassName(config.getString("jdbc.driver"));
		this.dataSource.setUsername(config.getString("jdbc.username"));
		this.dataSource.setPassword(config.getString("jdbc.password"));
		this.dataSource.setUrl(config.getString("jdbc.url"));

		// 配置初始化大小、最小、最大
		this.dataSource.setMinIdle(1);
		this.dataSource.setInitialSize(1);
		this.dataSource.setMaxWait(60000);// 配置获取连接等待超时的时间
		this.dataSource.setMaxActive(1000);

		this.dataSource.setFilters("slf4j");

		this.dataSource.setTestOnBorrow(false);
		this.dataSource.setTestOnReturn(false);
		this.dataSource.setTestWhileIdle(true);

		this.dataSource.setValidationQuery("SELECT 1;");
		this.dataSource.setValidationQueryTimeout(30000);

		this.dataSource.setMinEvictableIdleTimeMillis(300000);// 配置一个连接在池中最小生存的时间，单位是毫秒
		this.dataSource.setTimeBetweenEvictionRunsMillis(60000);// 配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒
	}

	@Override
	public void destroy() throws Exception {
		this.dataSource.close();
	}

	@Override
	public void close() throws Exception {
		DatabaseConnoction connoction = local.get();
		if (connoction == null) return;

		connoction.close();
		local.remove();
	}
}
